using System;
using System.Text;
using com.bodurov.SilverlightControls.XmlCodeEditor.Enums;

namespace com.bodurov.SilverlightControls.XmlCodeEditor.Extensions
{
    public static class String_Ext
    {
        public static string[] SplitAndRetainDelimiter(this string str, char[] chars)
        {
            return str.SplitAndRetainDelimiter(chars, Int32.MaxValue);
        }
        public static string[] SplitAndRetainDelimiter(this string str, char[] chars, int maxNumberPartsWithoutDelimiters)
        {
            if (str == null) return null;
            if (str == String.Empty) return new[] { String.Empty };
            if (maxNumberPartsWithoutDelimiters <= 1)
                throw new ArgumentException("Maximum number of parts to split and retain delimiter (not considering delimiters) must be more than 1, while it is " + maxNumberPartsWithoutDelimiters);
            var parts = new string[str.Length * 2];
            var sb = new StringBuilder();
            var j = 0;
            var p = 1;
            for (var i = 0; i < str.Length; i++)
            {
                var curr = str[i];
                if(p < maxNumberPartsWithoutDelimiters && CharIsIn(curr, chars))
                {
                    p++;
                    parts[j++] = sb.ToString();
                    if (sb.Length > 0)
                    {
                        sb.Clear();
                    }
                    parts[j++] = curr.ToString();
                    continue;
                }
                sb.Append(curr);
            }
            if ((j + 1) < parts.Length) parts[j++] = sb.ToString();
            else if (j == 0 && parts[0] == null && sb.Length > 0)
            {
                parts[0] = sb.ToString();
                j = 1;
            }
            if(j < parts.Length) Array.Resize(ref parts, j);
            return parts;
        }

        public static string[] SetMaxElements(this string[] array, int max)
        {
            if (array == null || array.Length <= max || array.Length == 0) return array;
            if (max <= 0) throw new ArgumentException("When setting max number of array elements, it cannot be 0 or negative, it is: "+max);
            var sb = new StringBuilder();
            for(var i = max - 1; i < array.Length; i++)
            {
                sb.Append(array[i]);
            }
            array[max - 1] = sb.ToString();
            if (max < array.Length) Array.Resize(ref array, max);
            return array;
        }

        private static readonly char[] _quoteChars = new[] {'\'', '"'};
        public static string[] SplitQuotedStrings(this string str)
        {
            var parts = str.SplitAndRetainDelimiter(_quoteChars);
            if (parts.Length <= 1) return parts;
            var elements = new string[parts.Length];
            var elem = XmlArea.InsideTag;
            var last = "";
            var j = 0;
            var sb = new StringBuilder();
            for(var i = 0; i < parts.Length; i++)
            {
                var current = parts[i];
                if (elem == XmlArea.InsideTag)
                {
                    if (current == "\"" && !last.EndsWith("\\"))
                    {
                        elem = XmlArea.InsideDualQuoteString;
                        sb.Append(current);
                    }
                    else if (current == "'" && !last.EndsWith("\\"))
                    {
                        elem = XmlArea.InsideSingleQuoteString;
                        sb.Append(current);
                    }
                    else if (current != "")
                    {
                        elements[j++] = current;
                    }
                }
                else if (elem == XmlArea.InsideDualQuoteString)
                {
                    if (current == "\"" && !last.EndsWith("\\")) // ends
                    {
                        elem = XmlArea.InsideTag;
                        sb.Append(current);
                        elements[j++] = sb.ToString();
                        sb.Clear();
                    }
                    else sb.Append(current);
                }
                else if (elem == XmlArea.InsideSingleQuoteString)
                {
                    if (current == "'" && !last.EndsWith("\\")) // ends
                    {
                        elem = XmlArea.InsideTag;
                        sb.Append(current);
                        elements[j++] = sb.ToString();
                        sb.Clear();
                    }
                    else sb.Append(current);
                }
                last = current;
            }
            if (elem == XmlArea.InsideDualQuoteString || elem == XmlArea.InsideSingleQuoteString && sb.Length > 0)
            {
                elements[j++] = sb.ToString();
            }
            if (j < elements.Length) Array.Resize(ref elements, j);
            return elements;
        }

        private static bool CharIsIn(char curr, char[] chars)
        {
            for (var i = 0; i < chars.Length; i++)
            {
                if (chars[i] == curr) return true;
            }
            return false;
        }
    }
}